package com.niiwoo.civet.trade.service.local.newRefund.notify.dubbo;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.Tuple2;
import com.niiwoo.civet.trade.enums.InvestorCreditorStatusEnum;
import com.niiwoo.civet.trade.service.local.intelligenceInvest.ProjectPackageLocalService;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.account.dto.common.sendmessage.InvestReceiveAdvanceDTO;
import com.niiwoo.civet.account.service.MessageSendDubboService;
import com.niiwoo.civet.trade.constant.DatePatternConstant;
import com.niiwoo.civet.trade.dto.InvestReceiveAmountDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.RefundNotifyHandle;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyHandleResult;
import com.niiwoo.civet.trade.service.local.newRefund.notify.enums.RefundNotifyEnum;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MessageInvestorReceiveNotify implements RefundNotifyHandle {
	
	@Autowired
	private ProjectInvestorPlanMapperExt projectInvestorPlanMapper;
	
	@Reference(version = "1.0.0")
	private MessageSendDubboService messageSendDubboService;

	@Autowired
	private ProjectPackageLocalService projectPackageLocalService;

	@Autowired
	private ProjectPackageDetailMapperExt projectPackageDetailMapperExt;

	@Autowired
	private ProjectPackageMapperExt projectPackageMapperExt;

	@Autowired
	private ProjectPackageInvestOrderMapperExt projectPackageInvestOrderMapperExt;

	@Autowired
	private ProjectPackageInvestOrderDetailMapperExt projectPackageInvestOrderDetailMapperExt;

	@Autowired
	private InvestorCreditorMapperExt investorCreditorMapperExt;

	@Override
	public RefundNotifyHandleResult handle(RefundNotifyDTO refundNotifyDTO) {
		RefundNotifyHandleResult refundNotifyHandleResult = null;
		try {
			RefundOrder refundOrder = refundNotifyDTO.getRefundOrder();
			InvestReceiveAdvanceDTO investReceiveAdvanceDTO = (InvestReceiveAdvanceDTO) bulidParam(refundNotifyDTO);
			if (investReceiveAdvanceDTO == null) return new RefundNotifyHandleResult();
			
			log.info("投资人-回款消息通知，RefundOrderId:{}，请求开始：{}", refundOrder.getId(), JSONObject.toJSONString(investReceiveAdvanceDTO));
			messageSendDubboService.sendLetterForInvestReceiveAdvance(refundOrder.getRefundType(), investReceiveAdvanceDTO);
			log.info("投资人-回款消息通知完成，RefundOrderId:{}", refundOrder.getId());
			refundNotifyHandleResult = new RefundNotifyHandleResult();
		} catch (Exception e) {
			refundNotifyHandleResult = new RefundNotifyHandleResult(e.getMessage());
			log.error("投资人-回款消息通知异常: 异常原因：{}, 请求参数：{}", e.getMessage(), JSONObject.toJSONString(refundNotifyDTO.getRefundNotifyRecord()), e);
		}
		return refundNotifyHandleResult;
	}
	
	@Override
	public Object bulidParam(RefundNotifyDTO refundNotifyDTO) {
		Project project = refundNotifyDTO.getProject();
		RefundNotifyRecord refundNotifyRecord = refundNotifyDTO.getRefundNotifyRecord();
		List<RefundOrderDetailBiz> refundOrderDetailBizList = refundNotifyDTO.getRefundOrderDetailBizList();
		
		// 统计投资订单统计本次回款金额
		InvestReceiveAmountDTO investReceiveAmountDTO = collectByInvestOrderIdForReceiveAmount(refundOrderDetailBizList, refundNotifyRecord.getInvestOrderId());
		
		// 回款金额为0直接返回
		if (investReceiveAmountDTO.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
			return null;
		}
		
		InvestReceiveAdvanceDTO investReceiveAdvanceDTO = new InvestReceiveAdvanceDTO();
		investReceiveAdvanceDTO.setProjectId(project.getProjectId());
		investReceiveAdvanceDTO.setProjectTitle(project.getTitle());
		investReceiveAdvanceDTO.setReceiveDate(FastDateFormat.getInstance(DatePatternConstant.YYYY_MM_DD).format(new Date()));
		investReceiveAdvanceDTO.setUserId(investReceiveAmountDTO.getInvestorUserId());
		investReceiveAdvanceDTO.setReceiveTotalAmount(investReceiveAmountDTO.getTotalAmount());
		investReceiveAdvanceDTO.setReceiveAmount(investReceiveAmountDTO.getTotalAmount());
		investReceiveAdvanceDTO.setReceiveCorpus(investReceiveAmountDTO.getCapital());
		investReceiveAdvanceDTO.setReceiveInterest(investReceiveAmountDTO.getInterest());
		investReceiveAdvanceDTO.setReceiveOverdueFine(investReceiveAmountDTO.getPenaltyFee());

		ProjectPackageInvestOrderDetail projectPackageInvestOrderDetail = projectPackageInvestOrderDetailMapperExt.selectByInvestOrderId(refundNotifyRecord.getInvestOrderId());

		investReceiveAdvanceDTO.setIsPackagedProject(projectPackageInvestOrderDetail != null);
		if(investReceiveAdvanceDTO.getIsPackagedProject()){
			ProjectPackageInvestOrder projectPackageInvestOrder = projectPackageInvestOrderMapperExt.selectByPrimaryKey(projectPackageInvestOrderDetail.getPackageInvestOrderId());
			investReceiveAdvanceDTO.setPackageInvestOrderSubmitTime(projectPackageInvestOrder.getCreateTime());

			ProjectPackage projectPackage = projectPackageMapperExt.selectByPrimaryKey(projectPackageDetailMapperExt.selectPackageIdByProjectId(project.getProjectId()));
			investReceiveAdvanceDTO.setPackageTitle(projectPackage.getTitle());
			investReceiveAdvanceDTO.setDeadline(projectPackage.getDeadline());
			investReceiveAdvanceDTO.setDeadlineUnit(projectPackage.getDeadlineUnit());

			if(RefundTypeEnum.OVERDEPT.getRefundType().equals(refundNotifyDTO.getRefundOrder().getRefundType())) {
				investReceiveAdvanceDTO.setPackageInvestOrderReceivedType(Byte.valueOf("1"));
			} else {
				investReceiveAdvanceDTO.setPackageInvestOrderReceivedType(Byte.valueOf("2"));
				Tuple2<Integer, BigDecimal> tuple2 = getCurrentPeriodPackageReceivedProjectNumAndReceivedTotalAmount(refundOrderDetailBizList, refundNotifyRecord.getInvestOrderId());
				investReceiveAdvanceDTO.setCurrentPeriodPackageReceivedProjectNum(tuple2.get_1());
				investReceiveAdvanceDTO.setCurrentPeriodPackageInvestOrderReceiveTotalAmount(tuple2.get_2());
			}

			Set<Long> investOrderIdSet = new HashSet<>();
			List<ProjectPackageInvestOrderDetail> projectPackageInvestOrderDetailList = projectPackageInvestOrderDetailMapperExt.selectByPackageInvestOrderId(projectPackageInvestOrderDetail.getPackageInvestOrderId());
			projectPackageInvestOrderDetailList.forEach(d -> investOrderIdSet.add(d.getInvestOrderId()));
			List<InvestorCreditor> investorCreditorList = investorCreditorMapperExt.selectByInvestOrderIds(investOrderIdSet);
			boolean finished = true;
			for(InvestorCreditor investorCreditor : investorCreditorList){
				if(InvestorCreditorStatusEnum.NORMAL_RECEIVING.getStatus().equals(investorCreditor.getStatus())
						|| InvestorCreditorStatusEnum.RECEIVE_OVERDUE.getStatus().equals(investorCreditor.getStatus())
						|| InvestorCreditorStatusEnum.TRANSFERRING.getStatus().equals(investorCreditor.getStatus())){
					finished = false;
					break;
				}
			}
			if(finished){
				investReceiveAdvanceDTO.setPackageInvestOrderReceivedType(Byte.valueOf("3"));
				BigDecimal packageInvestOrderReceiveCapital = BigDecimal.ZERO;
				BigDecimal packageInvestOrderReceiveInterest = BigDecimal.ZERO;
				BigDecimal packageInvestOrderReceivePenaltyFee = BigDecimal.ZERO;
				Set<Long> projectIdSet = new HashSet<>();
				for(InvestorCreditor investorCreditor : investorCreditorList){
					projectIdSet.add(investorCreditor.getProjectId());
					packageInvestOrderReceiveCapital = packageInvestOrderReceiveCapital.add(investorCreditor.getReceivedCapital());
					packageInvestOrderReceiveInterest = packageInvestOrderReceiveInterest.add(investorCreditor.getReceivedInterest());
					packageInvestOrderReceivePenaltyFee = packageInvestOrderReceivePenaltyFee.add(investorCreditor.getReceivedPenaltyFee());
				}
				BigDecimal packageInvestOrderReceiveTotalAmount = packageInvestOrderReceiveCapital.add(packageInvestOrderReceiveInterest).add(packageInvestOrderReceivePenaltyFee);

				investReceiveAdvanceDTO.setPackageInvestOrderReceivedProjectNum(projectIdSet.size());
				investReceiveAdvanceDTO.setPackageInvestOrderReceiveCapital(packageInvestOrderReceiveCapital);
				investReceiveAdvanceDTO.setPackageInvestOrderReceiveInterest(packageInvestOrderReceiveInterest);
				investReceiveAdvanceDTO.setPackageInvestOrderReceivePenaltyFee(packageInvestOrderReceivePenaltyFee);
				investReceiveAdvanceDTO.setPackageInvestOrderReceiveTotalAmount(packageInvestOrderReceiveTotalAmount);
			}

		}
		
		return investReceiveAdvanceDTO;
	}
	
	/**
	 * 根据回款计划ID汇总回款利息
	 * 
	 * @param refundOrderDetailBizList
	 * @param investOrderId
	 * @return
	 */
	private InvestReceiveAmountDTO collectByInvestOrderIdForReceiveAmount(List<RefundOrderDetailBiz> refundOrderDetailBizList, Long investOrderId) {
		InvestReceiveAmountDTO investReceiveAmountDTO = new InvestReceiveAmountDTO();
		investReceiveAmountDTO.setInvestOrderId(investOrderId);
		
		for (RefundOrderDetailBiz refundOrderDetailBiz : refundOrderDetailBizList) {
			// 回款金额小于0、非还款、代偿的直接跳过
			if (refundOrderDetailBiz.getAmount().compareTo(BigDecimal.ZERO) <= 0
					|| (!BusinessTypeEnum.REPAYMENT.name().equals(refundOrderDetailBiz.getBizType())
							&& !BusinessTypeEnum.COMPENSATORY.name().equals(refundOrderDetailBiz.getBizType()))) {
				continue;
			}
			
			ProjectInvestorPlan projectInvestorPlan = projectInvestorPlanMapper.selectByPrimaryKey(refundOrderDetailBiz.getBackPlanId());
			if (investOrderId.equals(projectInvestorPlan.getInvestOrderId())) {
				if (null == investReceiveAmountDTO.getInvestorUserId()) {
					investReceiveAmountDTO.setInvestorUserId(refundOrderDetailBiz.getTargetUserId());
				}
				investReceiveAmountDTO.setTotalAmount(investReceiveAmountDTO.getTotalAmount().add(refundOrderDetailBiz.getAmount()));
				investReceiveAmountDTO.setCapital(investReceiveAmountDTO.getCapital().add(refundOrderDetailBiz.getCapital()));
				investReceiveAmountDTO.setInterest(investReceiveAmountDTO.getInterest().add(refundOrderDetailBiz.getInterest()));
				investReceiveAmountDTO.setPenaltyFee(investReceiveAmountDTO.getPenaltyFee().add(refundOrderDetailBiz.getPenaltyFee()));
			}
		}
		return investReceiveAmountDTO;
	}

	private Tuple2<Integer, BigDecimal> getCurrentPeriodPackageReceivedProjectNumAndReceivedTotalAmount(List<RefundOrderDetailBiz> refundOrderDetailBizList, Long investOrderId) {
		Integer currentPeriodPackageReceivedProjectNum = null;
		BigDecimal currentPeriodReceivedTotalAmount = null;
		for (RefundOrderDetailBiz refundOrderDetailBiz : refundOrderDetailBizList) {
			// 回款金额小于0、非还款、代偿的直接跳过
			if (refundOrderDetailBiz.getAmount().compareTo(BigDecimal.ZERO) <= 0
					|| (!BusinessTypeEnum.REPAYMENT.name().equals(refundOrderDetailBiz.getBizType())
					&& !BusinessTypeEnum.COMPENSATORY.name().equals(refundOrderDetailBiz.getBizType()))) {
				continue;
			}

			ProjectInvestorPlan projectInvestorPlan = projectInvestorPlanMapper.selectByPrimaryKey(refundOrderDetailBiz.getBackPlanId());
			if (investOrderId.equals(projectInvestorPlan.getInvestOrderId())) {
				Integer currentPeriod = projectInvestorPlan.getCurrentPeriod();
				ProjectPackageInvestOrderDetail projectPackageInvestOrderDetail = projectPackageInvestOrderDetailMapperExt.selectByInvestOrderId(investOrderId);

				currentPeriodPackageReceivedProjectNum = projectInvestorPlanMapper.getCurrentPeriodPackageReceivedProjectNumByPackageInvestOrderIdAndPeriodAndUserId(projectPackageInvestOrderDetail.getPackageInvestOrderId(), currentPeriod, projectInvestorPlan.getUserId());

				currentPeriodReceivedTotalAmount = projectInvestorPlanMapper.getCurrentPeriodPackageReceivedTotalAmountByPackageInvestOrderIdAndPeriodAndUserId(projectPackageInvestOrderDetail.getPackageInvestOrderId(), currentPeriod, projectInvestorPlan.getUserId());
				break;
			}
		}

		Tuple2<Integer, BigDecimal> result = new Tuple2(currentPeriodPackageReceivedProjectNum, currentPeriodReceivedTotalAmount);
		return result;
	}

	@Override
	public RefundNotifyEnum getType() {
		return RefundNotifyEnum.MESSAGE_INVESTOR_RECEIVE;
	}	
}